{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xLOXFOT5Q40E"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "iiQkM5ZgQ8r2"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "j6331ZSsQGY3"
      },
      "source": [
        "# こんにちは、多くの世界"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "i9Jcnb8bQQyd"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/quantum/tutorials/hello_many_worlds\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">View on TensorFlow.org</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/quantum/tutorials/hello_many_worlds.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Run in Google Colab</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/quantum/tutorials/hello_many_worlds.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub でソースを表示{</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/quantum/tutorials/hello_many_worlds.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">ノートブックをダウンロード/a0}</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6tYn2HaAUgH0"
      },
      "source": [
        "このチュートリアルでは、古典的なニューラルネットワークが量子ビット・キャリブレーションエラーの訂正を学習する方法を紹介します。<a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq\" class=\"external\">Circq</a> は NISQ（ノイズの多い中間スケール量子）回路を作成、編集、呼び出すための Python フレームワークであり、ここでは Cirq が TensorFlow Quantum とどのようにやり取りするかを示します。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sPZoNKvpUaqa"
      },
      "source": [
        "## セットアップ"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "TorxE5tnkvb2"
      },
      "outputs": [],
      "source": [
        "!pip install tensorflow==2.1.0"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FxkQA6oblNqI"
      },
      "source": [
        "TensorFlow Quantum をインストールします。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "saFHsRDpkvkH"
      },
      "outputs": [],
      "source": [
        "!pip install tensorflow-quantum"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "F1L8h1YKUvIO"
      },
      "source": [
        "次に、TensorFlow とモジュールの依存関係をインポートします。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "enZ300Bflq80"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "import tensorflow_quantum as tfq\n",
        "\n",
        "import cirq\n",
        "import sympy\n",
        "import numpy as np\n",
        "\n",
        "# visualization tools\n",
        "%matplotlib inline\n",
        "import matplotlib.pyplot as plt\n",
        "from cirq.contrib.svg import SVGCircuit"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b08Mmbs8lr81"
      },
      "source": [
        "## 1. 基本"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y31qSRCczI-L"
      },
      "source": [
        "### 1.1 Cirq とパラメータ化された量子回路\n",
        "\n",
        "TensorFlow Quantum (TFQ) について説明する前に、<a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq\" class=\"external\">Circq</a> の基本をいくつか見てみましょう。Cirq は、Google の量子コンピューティング用の Python ライブラリで、静的ゲートやパラメータ化されたゲートなどの回路の定義に使用します。\n",
        "\n",
        "Cirq は、<a target=\"_blank\" href=\"https://www.sympy.org\" class=\"external\">SymPy</a> シンボルを使用して自由パラメータを表します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2yQdmhQLCrzQ"
      },
      "outputs": [],
      "source": [
        "a, b = sympy.symbols('a b')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "itUlpbKmDYNW"
      },
      "source": [
        "次のコードは、上記のパラメータを使用して 2 つの量子ビット回路を作成します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Ps-pd2mndXs7"
      },
      "outputs": [],
      "source": [
        "# Create two qubits\n",
        "q0, q1 = cirq.GridQubit.rect(1, 2)\n",
        "\n",
        "# Create a circuit on these qubits using the parameters you created above.\n",
        "circuit = cirq.Circuit(\n",
        "    cirq.rx(a).on(q0),\n",
        "    cirq.ry(b).on(q1), cirq.CNOT(control=q0, target=q1))\n",
        "\n",
        "SVGCircuit(circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zcCX109cJUaz"
      },
      "source": [
        "回路を評価するには、`cirq.Simulator`インターフェースを使用します。回路内の自由パラメータを特定の数値に置き換えるには、`cirq.ParamResolver`オブジェクトを渡します。以下のコードは、パラメータ化された回路の生の状態ベクトル出力を計算します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VMq7EayNRyQb"
      },
      "outputs": [],
      "source": [
        "# Calculate a state vector with a=0.5 and b=-0.5.\n",
        "resolver = cirq.ParamResolver({a: 0.5, b: -0.5})\n",
        "output_state_vector = cirq.Simulator().simulate(circuit, resolver).final_state\n",
        "output_state_vector"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-SUlLpXBeicF"
      },
      "source": [
        "状態ベクトルは、シミュレーションの外から直接アクセスすることはできません（上記の複素数出力に注意してください）。物理的に現実的にするには、状態ベクトルを古典的コンピュータが理解できる実数に変換する測定値を指定する必要があります。Cirq は、<a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/Pauli_matrices\" class=\"external\">Pauli 演算子</a> $\\hat{X}$, $\\hat{Y}$ および $\\hat{Z}$ の組み合わせを使用して測定値を指定します。例として、次のコードは、シミュレーションした状態ベクトルで $\\hat{Z}_0$ と $\\frac{1}{2}\\hat{Z}_0 + \\hat{X}_1$ を測定します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "hrSnOCi3ehr_"
      },
      "outputs": [],
      "source": [
        "z0 = cirq.Z(q0)\n",
        "\n",
        "qubit_map={q0: 0, q1: 1}\n",
        "\n",
        "z0.expectation_from_wavefunction(output_state_vector, qubit_map).real"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OZ0lWFXv6pII"
      },
      "outputs": [],
      "source": [
        "z0x1 = 0.5 * z0 + cirq.X(q1)\n",
        "\n",
        "z0x1.expectation_from_wavefunction(output_state_vector, qubit_map).real"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bkC-yjIolDNr"
      },
      "source": [
        "### 1.2 テンソルとしての量子回路\n",
        "\n",
        "TensorFlow Quantum (TFQ) は、Cirq オブジェクトをテンソルに変換する関数である`tfq.convert_to_tensor`を提供します。これにより、Cirq オブジェクトを<a target=\"_blank\" href=\"https://www.tensorflow.org/quantum/api_docs/python/tfq/layers\">量子レイヤー</a>および<a target=\"_blank\" href=\"https://www.tensorflow.org/quantum/api_docs/python/tfq/get_expectation_op\">量子演算</a>に送信できます。この関数は、Cirq Circuits と Cirq Paulis のリストまたは配列で呼び出すことができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1gLQjA02mIyy"
      },
      "outputs": [],
      "source": [
        "# Rank 1 tensor containing 1 circuit.\n",
        "circuit_tensor = tfq.convert_to_tensor([circuit])\n",
        "\n",
        "print(circuit_tensor.shape)\n",
        "print(circuit_tensor.dtype)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SJy6AkbU6pIP"
      },
      "source": [
        "これは、Cirq オブジェクトを`tf.string`テンソルとしてエンコードし、`tfq`演算は必要に応じてデコードします。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "aX_vEmCKmpQS"
      },
      "outputs": [],
      "source": [
        "# Rank 1 tensor containing 2 Pauli operators.\n",
        "pauli_tensor = tfq.convert_to_tensor([z0, z0x1])\n",
        "pauli_tensor.shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FI1JLWe6m8JF"
      },
      "source": [
        "### 1.3 バッチ回路シミュレーション\n",
        "\n",
        "TFQ は、期待値、サンプル、および状態ベクトルを計算するためのメソッドを提供します。まず、*期待値*から見ていきましょう。\n",
        "\n",
        "期待値を計算するための最高レベルのインターフェースは、`tf.keras.Layer`である`tfq.layers.Expectation`レイヤーです。最も単純な形式では、このレイヤーは、多くの`cirq.ParamResolvers`でパラメータ化された回路をシミュレートすることと同等ですが、TFQ では TensorFlow セマンティクスに従ったバッチ処理が可能であり、回路は効率的な C++ コードを使用してシミュレートされます。\n",
        "\n",
        "`a`と`b`パラメータの代わりに値のバッチを作成します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1fsVZhF5lIXp"
      },
      "outputs": [],
      "source": [
        "batch_vals = np.array(np.random.uniform(0, 2 * np.pi, (5, 2)), dtype=np.float32)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ip7jlGXIf22u"
      },
      "source": [
        "Cirq のパラメータ値に対するバッチ回路の実行には、ループが必要です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RsfF53UCJtr9"
      },
      "outputs": [],
      "source": [
        "cirq_results = []\n",
        "cirq_simulator = cirq.Simulator()\n",
        "\n",
        "for vals in batch_vals:\n",
        "    resolver = cirq.ParamResolver({a: vals[0], b: vals[1]})\n",
        "    final_state = cirq_simulator.simulate(circuit, resolver).final_state\n",
        "    cirq_results.append(\n",
        "        [z0.expectation_from_wavefunction(final_state, {\n",
        "            q0: 0,\n",
        "            q1: 1\n",
        "        }).real])\n",
        "\n",
        "print('cirq batch results: \\n {}'.format(np.array(cirq_results)))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "W0JlZEu-f9Ac"
      },
      "source": [
        "TFQ では同じ演算が簡略化されています。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kGZVdcZ6y9lC"
      },
      "outputs": [],
      "source": [
        "tfq.layers.Expectation()(circuit,\n",
        "                         symbol_names=[a, b],\n",
        "                         symbol_values=batch_vals,\n",
        "                         operators=z0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wppQ3TJ23mWC"
      },
      "source": [
        "## 2. 量子古典ハイブリッドの最適化\n",
        "\n",
        "以上は基本の説明でした。次に、TensorFlow Quantum を使用して*量子古典ハイブリッドニューラルネット*を構築しましょう。古典的なニューラルネットをトレーニングして、1 つの量子ビットを制御します。コントロールは、`0`または`1`の状態の量子ビットを正しく準備するように最適化され、シミュレートされた系統的なキャリブレーションエラーを克服します。以下の図は、アーキテクチャを示しています。\n",
        "\n",
        " <img src=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/quantum/tutorials/images/nn_control1.png?raw=true\" class=\"\">\n",
        "\n",
        "これはニューラルネットワークがなくても簡単に解決できる問題ですが、テーマは TFQ を使用して解決できる実際の量子制御の問題と似ています。これは、`tf.keras.Model`内の`tfq.layers.ControlledPQC` (Parametrized Quantum Circuit) レイヤーを使用した量子古典計算のエンドツーエンドの例を示しています。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NlyxF3Q-6pIe"
      },
      "source": [
        "このチュートリアルの実装では、アーキテクチャは 3 つの部分に分かれています。\n",
        "\n",
        "- *入力回路*または*データポイント回路*：最初の 3 つの $R$ ゲート。\n",
        "- *制御回路*：その他の 3 つの $R$ ゲート。\n",
        "- *コントローラ*：制御回路のパラメータを設定する古典的なニューラルネットワーク。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VjDf-nTM6ZSs"
      },
      "source": [
        "### 2.1 制御回路の定義\n",
        "\n",
        "上の図に示すように、学習可能なシングルビットローテーションを定義します。これは、制御回路に対応します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "N-j7SCl-51-q"
      },
      "outputs": [],
      "source": [
        "# Parameters that the classical NN will feed values into.\n",
        "control_params = sympy.symbols('theta_1 theta_2 theta_3')\n",
        "\n",
        "# Create the parameterized circuit.\n",
        "qubit = cirq.GridQubit(0, 0)\n",
        "model_circuit = cirq.Circuit(\n",
        "    cirq.rz(control_params[0])(qubit),\n",
        "    cirq.ry(control_params[1])(qubit),\n",
        "    cirq.rx(control_params[2])(qubit))\n",
        "\n",
        "SVGCircuit(model_circuit)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wfjSbsvb7g9f"
      },
      "source": [
        "### 2.2 コントローラ\n",
        "\n",
        "次に、コントローラネットワークを定義します。 "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1v4CK2jD6pIj"
      },
      "outputs": [],
      "source": [
        "# The classical neural network layers.\n",
        "controller = tf.keras.Sequential([\n",
        "    tf.keras.layers.Dense(10, activation='elu'),\n",
        "    tf.keras.layers.Dense(3)\n",
        "])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QNimbsAt6pIm"
      },
      "source": [
        "コントローラにコマンドのバッチを与えると、制御された回路の制御信号のバッチが出力されます。\n",
        "\n",
        "コントローラはランダムに初期化されるため、これらの出力はまだ有用ではありません。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kZbYRTe16pIm"
      },
      "outputs": [],
      "source": [
        "controller(tf.constant([[0.0],[1.0]])).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XizLExg56pIp"
      },
      "source": [
        "### 2.3 コントローラを回路に接続する"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "I5Pmy5-V6pIq"
      },
      "source": [
        "`tfq`を使用して、コントローラを 1 つの`keras.Model`として制御回路に接続します。\n",
        "\n",
        "このスタイルのモデル定義の詳細については、[Keras Functional API ガイド](https://www.tensorflow.org/guide/keras/functional)をご覧ください。\n",
        "\n",
        "まず、モデルへの入力を定義します。 "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UfHF8NNE6pIr"
      },
      "outputs": [],
      "source": [
        "# This input is the simulated miscalibration that the model will learn to correct.\n",
        "circuits_input = tf.keras.Input(shape=(),\n",
        "                                # The circuit-tensor has dtype `tf.string` \n",
        "                                dtype=tf.string,\n",
        "                                name='circuits_input')\n",
        "\n",
        "# Commands will be either `0` or `1`, specifying the state to set the qubit to.\n",
        "commands_input = tf.keras.Input(shape=(1,),\n",
        "                                dtype=tf.dtypes.float32,\n",
        "                                name='commands_input')\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y9xN2mNl6pIu"
      },
      "source": [
        "次に、これらの入力に演算を適用して、計算を定義します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Zvt2YGmZ6pIu"
      },
      "outputs": [],
      "source": [
        "dense_2 = controller(commands_input)\n",
        "\n",
        "# TFQ layer for classically controlled circuits.\n",
        "expectation_layer = tfq.layers.ControlledPQC(model_circuit,\n",
        "                                             # Observe Z\n",
        "                                             operators = cirq.Z(qubit))\n",
        "expectation = expectation_layer([circuits_input, dense_2])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ip2jNA9h6pIy"
      },
      "source": [
        "次に、この計算を`tf.keras.Model`としてパッケージ化します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Xs6EMhah6pIz"
      },
      "outputs": [],
      "source": [
        "# The full Keras model is built from our layers.\n",
        "model = tf.keras.Model(inputs=[circuits_input, commands_input],\n",
        "                       outputs=expectation)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "w7kgqm3t6pI3"
      },
      "source": [
        "ネットワークアーキテクチャは、以下のモデルのプロットで示されています。このモデルプロットをアーキテクチャ図と比較して、正確さを確認します。\n",
        "\n",
        "注意: `graphviz`パッケージのシステムインストールが必要になる場合があります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ERXNPe4F6pI4"
      },
      "outputs": [],
      "source": [
        "tf.keras.utils.plot_model(model, show_shapes=True, dpi=70)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-Pbemgww6pI7"
      },
      "source": [
        "このモデルは、コントローラのコマンドと、コントローラが出力を修正しようとしている入力回路の 2 つの入力を受け取ります。 "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hpnIBK916pI8"
      },
      "source": [
        "### 2.4 データセット"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yJSC9qH76pJA"
      },
      "source": [
        "モデルは、コマンドごとに $\\hat{Z}$ の正しい測定値の出力を試行します。コマンドと正しい値の定義は以下のとおりです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ciMIJAuH6pJA"
      },
      "outputs": [],
      "source": [
        "# The command input values to the classical NN.\n",
        "commands = np.array([[0], [1]], dtype=np.float32)\n",
        "\n",
        "# The desired Z expectation value at output of quantum circuit.\n",
        "expected_outputs = np.array([[1], [-1]], dtype=np.float32)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kV1LM_hZ6pJD"
      },
      "source": [
        "これは、このタスクのトレーニングデータセット全体ではありません。データセット内の各データポイントにも入力回路が必要です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bbiVHvSYVW4H"
      },
      "source": [
        "### 2.4 入力回路の定義\n",
        "\n",
        "以下の入力回路は、モデルが修正することを学習するためのランダムな誤校正を定義します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_VYfzHffWo7n"
      },
      "outputs": [],
      "source": [
        "random_rotations = np.random.uniform(0, 2 * np.pi, 3)\n",
        "noisy_preparation = cirq.Circuit(\n",
        "  cirq.rx(random_rotations[0])(qubit),\n",
        "  cirq.ry(random_rotations[1])(qubit),\n",
        "  cirq.rz(random_rotations[2])(qubit)\n",
        ")\n",
        "datapoint_circuits = tfq.convert_to_tensor([\n",
        "  noisy_preparation\n",
        "] * 2)  # Make two copied of this circuit"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FvOkMyKI6pJI"
      },
      "source": [
        "回路には 2 つのコピーがあります（データポイントごとに 1 つずつ）。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6nk2Yr3e6pJJ"
      },
      "outputs": [],
      "source": [
        "datapoint_circuits.shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gB--UhZZYgVY"
      },
      "source": [
        "### 2.5 トレーニング"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jATjqUIv6pJM"
      },
      "source": [
        "定義された入力を使用して、`tfq`モデルのテストランを実行します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Lwphqvs96pJO"
      },
      "outputs": [],
      "source": [
        "model([datapoint_circuits, commands]).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9gyg5qSL6pJR"
      },
      "source": [
        "次に、標準のトレーニングプロセスを実行して、これらの値を`expected_outputs`に向けて調整します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dtPYqbNi8zeZ"
      },
      "outputs": [],
      "source": [
        "optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)\n",
        "loss = tf.keras.losses.MeanSquaredError()\n",
        "model.compile(optimizer=optimizer, loss=loss)\n",
        "history = model.fit(x=[datapoint_circuits, commands],\n",
        "                    y=expected_outputs,\n",
        "                    epochs=30,\n",
        "                    verbose=0)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "azE-qV0OaC1o"
      },
      "outputs": [],
      "source": [
        "plt.plot(history.history['loss'])\n",
        "plt.title(\"Learning to Control a Qubit\")\n",
        "plt.xlabel(\"Iterations\")\n",
        "plt.ylabel(\"Error in Control\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GTd5DGcRmmOK"
      },
      "source": [
        "このプロットから、ニューラルネットワークが体系的なキャリブレーションエラーを訂正することを学習したことがわかります。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "C2RfWismj66S"
      },
      "source": [
        "### 2.6 出力の確認\n",
        "\n",
        "次に、トレーニング済みモデルを使用して、量子ビット・キャリブレーションエラーを修正します。Cirq を使用する場合は以下のとおりです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RoIlb7r7j5SY"
      },
      "outputs": [],
      "source": [
        "def check_error(command_values, desired_values):\n",
        "  \"\"\"Based on the value in `command_value` see how well you could prepare\n",
        "  the full circuit to have `desired_value` when taking expectation w.r.t. Z.\"\"\"\n",
        "  params_to_prepare_output = controller(command_values).numpy()\n",
        "  full_circuit = noisy_preparation + model_circuit\n",
        "\n",
        "  # Test how well you can prepare a state to get expectation the expectation\n",
        "  # value in `desired_values`\n",
        "  for index in [0, 1]:\n",
        "    state = cirq_simulator.simulate(\n",
        "        full_circuit,\n",
        "        {s:v for (s,v) in zip(control_params, params_to_prepare_output[index])}\n",
        "    ).final_state\n",
        "    expectation = z0.expectation_from_wavefunction(state, {qubit: 0}).real\n",
        "    print(f'For a desired output (expectation) of {desired_values[index]} with'\n",
        "          f' noisy preparation, the controller\\nnetwork found the following '\n",
        "          f'values for theta: {params_to_prepare_output[index]}\\nWhich gives an'\n",
        "          f' actual expectation of: {expectation}\\n')\n",
        "\n",
        "\n",
        "check_error(commands, expected_outputs)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wvW_ZDwmsws6"
      },
      "source": [
        "トレーニング中の損失関数の値から、モデルの学習がどれほど進んでいるかが大まかに分かります。損失が小さいほど、上記のセルの期待値は`Desired_values`に近くなります。パラメータ値に関心がない場合は、`tfq`を使用して上記からの出力をいつでも確認できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "aYskLTacs8Ku"
      },
      "outputs": [],
      "source": [
        "model([datapoint_circuits, commands])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jNrW0NXR-lDC"
      },
      "source": [
        "## 3 さまざまな演算子の固有状態の準備について学ぶ\n",
        "\n",
        "1 と 0 に対応する $\\pm \\hat{Z}$ 固有状態の選択は任意でした。1 を $+ \\hat{Z}$ 固有状態に対応させ、0 を $-\\hat{X}$ 固有状態に対応させることも簡単にできます。そのためには、次の図に示すように、コマンドごとに異なる測定演算子を指定します。\n",
        "\n",
        " <img src=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/quantum/tutorials/images/nn_control2.png?raw=true\" class=\"\">\n",
        "\n",
        "これには、<code>tfq.layers.Expectation</code>を使用する必要があります。これで、入力は、回路、コマンド、および演算子の 3 つのオブジェクトを含むようになりました。出力は期待値のままです。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ci3WMZ9CjEM1"
      },
      "source": [
        "### 3.1 新しいモデルの定義\n",
        "\n",
        "このタスクを実行するためのモデルを見てみましょう。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "hta0G3Nc6pJY"
      },
      "outputs": [],
      "source": [
        "# Define inputs.\n",
        "commands_input = tf.keras.layers.Input(shape=(1),\n",
        "                                       dtype=tf.dtypes.float32,\n",
        "                                       name='commands_input')\n",
        "circuits_input = tf.keras.Input(shape=(),\n",
        "                                # The circuit-tensor has dtype `tf.string` \n",
        "                                dtype=tf.dtypes.string,\n",
        "                                name='circuits_input')\n",
        "operators_input = tf.keras.Input(shape=(1,),\n",
        "                                 dtype=tf.dtypes.string,\n",
        "                                 name='operators_input')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dtdnkrZm6pJb"
      },
      "source": [
        "コントローラネットワークは次のとおりです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "n_aTG4g3-y0F"
      },
      "outputs": [],
      "source": [
        "# Define classical NN.\n",
        "controller = tf.keras.Sequential([\n",
        "    tf.keras.layers.Dense(10, activation='elu'),\n",
        "    tf.keras.layers.Dense(3)\n",
        "])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "q9aN2ciy6pJf"
      },
      "source": [
        "`tfq`を使用して、回路とコントローラを 1 つの`keras.Model`に結合します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IMHjiKit6pJg"
      },
      "outputs": [],
      "source": [
        "dense_2 = controller(commands_input)\n",
        "\n",
        "# Since you aren't using a PQC or ControlledPQC you must append\n",
        "# your model circuit onto the datapoint circuit tensor manually.\n",
        "full_circuit = tfq.layers.AddCircuit()(circuits_input, append=model_circuit)\n",
        "expectation_output = tfq.layers.Expectation()(full_circuit,\n",
        "                                              symbol_names=control_params,\n",
        "                                              symbol_values=dense_2,\n",
        "                                              operators=operators_input)\n",
        "\n",
        "# Contruct your Keras model.\n",
        "two_axis_control_model = tf.keras.Model(\n",
        "    inputs=[circuits_input, commands_input, operators_input],\n",
        "    outputs=[expectation_output])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VQTM6CCiD4gU"
      },
      "source": [
        "### 3.2 データセット\n",
        "\n",
        "`model_circuit`に提供する各データポイントに対して測定する演算子も含めます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4gw_L3JG0_G0"
      },
      "outputs": [],
      "source": [
        "# The operators to measure, for each command.\n",
        "operator_data = tfq.convert_to_tensor([[cirq.X(qubit)], [cirq.Z(qubit)]])\n",
        "\n",
        "# The command input values to the classical NN.\n",
        "commands = np.array([[0], [1]], dtype=np.float32)\n",
        "\n",
        "# The desired expectation value at output of quantum circuit.\n",
        "expected_outputs = np.array([[1], [-1]], dtype=np.float32)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ALCKSvwh0_G2"
      },
      "source": [
        "### 3.3トレーニング\n",
        "\n",
        "新しい入力と出力を使用し、keras でもう一度トレーニングします。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nFuGA73MAA4p"
      },
      "outputs": [],
      "source": [
        "optimizer = tf.keras.optimizers.Adam(learning_rate=0.05)\n",
        "loss = tf.keras.losses.MeanSquaredError()\n",
        "\n",
        "two_axis_control_model.compile(optimizer=optimizer, loss=loss)\n",
        "\n",
        "history = two_axis_control_model.fit(\n",
        "    x=[datapoint_circuits, commands, operator_data],\n",
        "    y=expected_outputs,\n",
        "    epochs=30,\n",
        "    verbose=1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Cf_G-GdturLL"
      },
      "outputs": [],
      "source": [
        "plt.plot(history.history['loss'])\n",
        "plt.title(\"Learning to Control a Qubit\")\n",
        "plt.xlabel(\"Iterations\")\n",
        "plt.ylabel(\"Error in Control\")\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sdCPDH9NlJBl"
      },
      "source": [
        "損失関数はゼロに低下しました。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NzY8eSVm6pJs"
      },
      "source": [
        "`controller`はスタンドアロンモデルとして利用できます。コントローラを呼び出し、各コマンド信号に対する応答を確認します。多少手間がかかりますが、これらの出力を`random_rotations`の内容と比較します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uXmH0TQ76pJt"
      },
      "outputs": [],
      "source": [
        "controller.predict(np.array([0,1]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "n2WtXnsxubD2"
      },
      "source": [
        "成功: 最初のモデルの`check_error`関数を、この新しいモデルアーキテクチャで動作するように適合させることができるかどうかを確認します。"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "hello_many_worlds.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
